﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace KStarProxy
{
    class KStarProxy
    {
        const int ERRORMSG_LENGTH = 256;
        const int RECORD_LENGTH = 400;
        const int RECORDS_COUNT_EACH_TIME = 50;
        const int TIMEOUT = 2000;
        private ushort Port = 8089;

        public event KStarDataReceivedHandler DataReceived;

        private Thread _receiveThread;
        private ManualResetEvent _stopEvent = new ManualResetEvent(false);
        private Thread _connectionThread;
        private ManualResetEvent _proxyStarted = new ManualResetEvent(false);
        private ManualResetEvent _receiveError = new ManualResetEvent(false);
        private ManualResetEvent _receiveThreadExit = new ManualResetEvent(false);

        private static KStarProxy _instance = new KStarProxy();
        private KStarProxy() { }
        public static KStarProxy GetInstance() { return _instance; }

        private object _lockObj = new object();

        public void Start()
        {
            lock (this._lockObj)
            {
                if (this.CurrentStatus == Status.Started)
                    return;
                this.CurrentStatus = Status.Starting;
                this._stopEvent.Reset();
                this._proxyStarted.Reset();
                this._receiveError.Reset();
                createReceiveThread();
                createConnectionThread();
                this.CurrentStatus = Status.Started;
            }
        }

        public void Stop()
        {
            lock (this._lockObj)
            {
                if (this.CurrentStatus == Status.Stopped)
                    return;
                this.CurrentStatus = Status.Stopping;
                this._stopEvent.Set();
                this._receiveThreadExit.WaitOne();
                tryStopProxy();
                this.CurrentStatus = Status.Stopped;
            }
        }

        private void createConnectionThread()
        {
            this._connectionThread = new Thread(new ThreadStart(connectionProcessor));
            this._connectionThread.Start();
            Thread.Sleep(0);
        }
        private void connectionProcessor()
        {
            while (true)
            {
                try
                {
                    startProxy();
                    this._proxyStarted.Set();
                    int index = AutoResetEvent.WaitAny(new WaitHandle[] { this._stopEvent, this._receiveError });
                    if (index == 0)
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    int index = AutoResetEvent.WaitAny(new WaitHandle[] { this._stopEvent }, 2000);
                    if (index == 0)
                    {
                        break;
                    }
                }
            }
        }
        private void startProxy()
        {
            StringBuilder msg = new StringBuilder(ERRORMSG_LENGTH);
            bool startSucceed = KStarAPI.KSFTHQPUB_Start(Port, msg);
            if (!startSucceed)
                throw new Exception(msg.ToString());
        }

        private void createReceiveThread()
        {
            ThreadStart ts = new ThreadStart(receiveProcessor);
            this._receiveThread = new Thread(ts);
            this._receiveThread.Start();
        }
        private void receiveProcessor()
        {
            while (true)
            {
                if (_stopEvent.WaitOne(0))//检查停止事件是否发生
                    break;
                try
                {
                    this._proxyStarted.WaitOne();
                    var data = getQuotData();
                    if (data != null && data.Any())
                        onDataReceived(data);
                }
                catch (Exception ex)
                {
                    this._receiveError.Set();
                    this._proxyStarted.Reset();
                }

            }
            this._receiveThreadExit.Set();
        }
        private IEnumerable<KStarAPI.KSFT_QUOTA_PUBDATA_ITEM> getQuotData()
        {
            KStarAPI.KSFT_QUOTA_PUBDATA_ITEM[] data = new KStarAPI.KSFT_QUOTA_PUBDATA_ITEM[RECORDS_COUNT_EACH_TIME];
            StringBuilder msg = new StringBuilder(ERRORMSG_LENGTH);
            int count = KStarAPI.KSFTHQPUB_GetQuota(data, RECORD_LENGTH * RECORDS_COUNT_EACH_TIME, TIMEOUT, msg);
            if (count > 0)
            {
                return data.Take(count);
            }
            else if (count < 0) //出错了
            {
                throw new Exception(msg.ToString());
            }
            else //无数据
            {
                return null;
            }
        }
        private void onDataReceived(IEnumerable<KStarAPI.KSFT_QUOTA_PUBDATA_ITEM> data)
        {
            KStarDataReceivedHandler handler = this.DataReceived;
            if (handler != null)
                handler(data);
        }


        private void tryStopProxy()
        {
            try
            {
                KStarAPI.KSFTHQPUB_Stop();
            }
            catch (Exception ex)
            {
            }

        }

        public Status CurrentStatus { get; private set; }

        public enum Status
        {
            Starting,
            Started,
            Stopping,
            Stopped
        }
    }
}
